/*
 * @Author: 0x9DEFA478
 * @Date: 2025-08-12 22:41:14
 * @LastEditTime: 2025-09-22 23:45:33
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#ifndef hH_String_HPP_
#define hH_String_HPP_
#include <string>
#include "H_Pointer.hpp"
#include "Memory/H_Allocator.hpp"


namespace H{

  namespace String{

    namespace Internal{
      
#if __cplusplus >= 202000L
      template<typename TypeChar,uint16 SegmentLength,Concept::allocator Allocator>
#else
      template<typename TypeChar,uint16 SegmentLength,typename Allocator>
#endif
      class FIFO_Base{
        static_assert(std::is_trivial_v<TypeChar>);

        private:

          struct Segment{
            Segment* Next;
            Segment* Last;
            uint16 Offset;
            uint16 Length;

            TypeChar data[SegmentLength];
          };

          using SegmentPool=Pool::ObjectInert<Allocator,sizeof(Segment)>;

        private:
          Segment* NewSegment(){
            auto r=static_cast<Segment*>(segmentPool.Alloc());
            r->Offset=0;
            r->Length=0;
            return r;
          }

          void FreeSegment(Segment* segment)noexcept{
            segmentPool.Free(static_cast<void*>(segment));
          }

          void CopyToThis(const FIFO_Base& fifo_base){
            Segment* p;
            Segment* dp;

            p=fifo_base.beginSeg;
            if(p==nullptr){
              return;
            }

            dp=NewSegment();
            *dp=*p;
            dp->Last=nullptr;
            dp->Next=nullptr;
            beginSeg=dp;

            p=p->Next;

            while(p!=nullptr){
              Segment* np;

              np=NewSegment();
              *np=*p;
              np->Last=dp;
              np->Next=nullptr;
              dp->Next=np;

              dp=np;
              p=p->Next;
            }

            endSeg=dp;
            charLength=fifo_base.charLength;
          }

        public:
          FIFO_Base():beginSeg(nullptr),endSeg(nullptr),charLength(0){}
          ~FIFO_Base()noexcept{
            Clear();
          }

          FIFO_Base(const FIFO_Base& fifo_base){
            CopyToThis(fifo_base);
          }
          FIFO_Base(FIFO_Base&& fifo_base)noexcept:beginSeg(fifo_base.beginSeg),endSeg(fifo_base.endSeg),charLength(fifo_base.charLength){
            fifo_base.beginSeg=nullptr;
            fifo_base.endSeg=nullptr;
            fifo_base.charLength=0;
          }

          FIFO_Base& operator=(const FIFO_Base& fifo_base){
            Clear();
            CopyToThis(fifo_base);
            return *this;
          }
          FIFO_Base& operator=(FIFO_Base&& fifo_base)noexcept{
            beginSeg=fifo_base.beginSeg;
            endSeg=fifo_base.endSeg;
            charLength=fifo_base.charLength;
            fifo_base.beginSeg=nullptr;
            fifo_base.endSeg=nullptr;
            fifo_base.charLength=0;
            return *this;
          }

          void Write(const TypeChar* String,usize Length){
            usize srcIndex;

            srcIndex=0;

            if(Length<1){
              return;
            }

            if(endSeg==nullptr){
              beginSeg=NewSegment();
              endSeg=beginSeg;

              beginSeg->Last=nullptr;
              beginSeg->Next=nullptr;
            }

            while(srcIndex<Length){
              uint16 segLen=endSeg->Length;
              uint16 index=endSeg->Offset+segLen;
              uint16 remanderLength=SegmentLength-index;

              if(remanderLength<1){
                auto seg=NewSegment();
                
                seg->Last=endSeg;
                seg->Next=nullptr;
                endSeg->Next=seg;

                endSeg=seg;

                segLen=0;
                index=0;
                remanderLength=SegmentLength;
              }

              uint16 writeLength=remanderLength;
              usize remanderSrc=Length-srcIndex;

              if(((usize)writeLength)>remanderSrc){
                writeLength=(uint16)remanderSrc;
              }

              for(uint16 i=0;i<writeLength;i++){
                endSeg->data[index+i]=String[srcIndex+i];
              }
              endSeg->Length=segLen+writeLength;
              srcIndex+=writeLength;
            }

            charLength+=Length;

          }

          void Write(const std::basic_string<TypeChar>& String){
            Write(String.c_str(),String.size());
          }

          usize Read(TypeChar* Buffer,usize BufferSize)noexcept{
            usize dstIndex;
            Segment* p;

            dstIndex=0;

            if(BufferSize<1){
              return 0;
            }

            p=beginSeg;
            while((p!=nullptr)&&(dstIndex<BufferSize)){
              uint16 length=p->Length;
              uint16 readLength=length;
              uint16 offset=p->Offset;
              usize remanderLength=BufferSize-dstIndex;
              
              if(readLength>remanderLength){
                readLength=remanderLength;
              }
              
              for(uint16 i=0;i<readLength;i++){
                Buffer[dstIndex+i]=p->data[offset+i];
              }

              dstIndex+=readLength;

              offset+=readLength;
              length-=readLength;
              if(length>0){
                p->Offset=offset;
                p->Length=length;
              }else{
                Segment* p_next;

                p_next=p->Next;
                if(p_next!=nullptr){
                  beginSeg=p_next;
                  p_next->Last=nullptr;
                }else{
                  beginSeg=nullptr;
                  endSeg=nullptr;
                }

                FreeSegment(p);
                p=p_next;
              }
              
            }

            charLength-=dstIndex;

            return dstIndex;
          }

          int FirstCharPos(TypeChar Char)const noexcept{
            Segment* p;
            int pos;

            pos=0;
            p=beginSeg;

            while(p!=nullptr){
              
              for(uint16 i=p->Offset,i_end=i+p->Length;i<i_end;i++){
                if(p->data[i]==Char){
                  return pos;
                }
                pos++;
                if(pos<0){
                  return pos;
                }
              }

              p=p->Next;
            }

            return -1;
          }

          bool ReadLine(Pointer<TypeChar>& Line,TypeChar EOL)noexcept{
            int len=FirstCharPos(EOL);
            if(len<0){
              return false;
            }

            auto buffer=H::Pointer<TypeChar>::Array(len+1);
            Read(&buffer[0],buffer.Length());

            Line=buffer.Clone(len);

            return true;
          }

          void Clear()noexcept{
            Segment* p;

            p=beginSeg;
            while(p!=nullptr){
              Segment* p_next=p->Next;
              segmentPool.Free(p);
              p=p_next;
            }

            beginSeg=nullptr;
            endSeg=nullptr;
            charLength=0;
          }

          usize Length()const noexcept{return charLength;}

          void Trim()noexcept{segmentPool.Trim();}

        private:
          Segment* beginSeg;
          Segment* endSeg;
          usize charLength;
          SegmentPool segmentPool;
      };

    }


#if __cplusplus >= 202000L
    template<typename TypeChar,uint16 SegmentLength=64,Concept::allocator Allocator=AllocatorDefault>
#else
    template<typename TypeChar,uint16 SegmentLength=64,typename Allocator=AllocatorDefault>
#endif
    class FIFO:public Internal::FIFO_Base<TypeChar,SegmentLength,Allocator>{
      public:
        using FIFO::FIFO_Base::FIFO_Base;
    };


    /**
     * @brief 判断字符串是否具有特定后缀
     * @param String 目标字符串
     * @param Suffix 后缀字符串
     * @param CaseInsensitive 是否大写小写不敏感
     * @return 0:String具有Suffix后缀 其他:String不具有Suffix后缀
     */
    bool IsSuffix(const std::string& String,const std::string& Suffix,bool CaseInsensitive=false);

    /**
     * @brief 格式化打印到字符串
     * @param Format 格式字符串
     * @param ... 附加参数
     * @return 输出的字符串
     */
    CheckPrintfFormat(0,1) std::string Format(const char* Format,...);

  }

}


#endif //hH_String_HPP_
